package com.gitee.wsl.mathematics.function.noise.d2

import com.gitee.wsl.ext.number.wrap
import com.gitee.wsl.mathematics.function.noise.Noise2d
import com.gitee.wsl.mathematics.vector.vec2.MutableVec2f
import kotlin.math.min
import kotlin.math.sqrt
import kotlin.random.Random

class WorleyNoise2d(val gridSizeX: Int, val gridSizeY: Int, seed: Int = 19937) : Noise2d {

    private val grid = Array(gridSizeX * gridSizeY) { MutableVec2f() }

    init {
        val rand = Random(seed)

        for (y in 0 until gridSizeY) {
            for (x in 0 until gridSizeX) {
                grid(x, y).set(x + rand.nextFloat(), y + rand.nextFloat())
            }
        }
    }

    private fun grid(x: Int, y: Int): MutableVec2f {
        val xw = x.wrap(0, gridSizeX)
        val yw = y.wrap(0, gridSizeY)
        return grid[yw * gridSizeX + xw]
    }

    override fun eval(x: Float, y: Float): Float {
        val px = x * gridSizeX
        val py = y * gridSizeY
        val ix = px.toInt()
        val iy = py.toInt()

        var d = MAX_D
        for (gy in iy-1 .. iy+1) {
            for (gx in ix - 1..ix + 1) {
                val v = grid(gx, gy)
                val dx = px - v.x
                val dy = py - v.y
                d = min(d, sqrt(dx * dx + dy * dy))
            }
        }
        return d / MAX_D
    }

    companion object {
        private val MAX_D = sqrt(2f)
    }
}

fun Noise2d.Companion.worley( gridSizeX: Int,  gridSizeY: Int, seed: Int = 19937) = WorleyNoise2d(gridSizeX, gridSizeY, seed)